package internal

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"golang.org/x/net/publicsuffix"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"
)

const (
	BaseUrl     = "https://studio-api.suno.ai"
	GetTokenUrl = "https://clerk.suno.com/v1/client/sessions"
	GetSidUrl   = "https://clerk.suno.com/v1/client?_clerk_js_version=4.72.0-snapshot.vc141245"

	ContentType    = "application/json"
	Complete       = "complete"
	TokenNotFound  = "token not found"
	CookieNotFound = "cookie not found"
)

var Token string

type service struct{}

var SunoService = new(service)

// Generate 发起生成请求
func (s *service) Generate(prompt string) (response GenerateResp, err error) {
	// token校验
	//if err = s.checkToken(); err != nil {
	//	return
	//}

	// 携带token发起请求
	genReq := GenerateReq{
		GptDescriptionPrompt: prompt,
		Mv:                   "chirp-v3-0",
	}
	reqData, _ := json.Marshal(genReq)
	genMusicUrl := BaseUrl + "/api/generate/v2/"
	req, _ := http.NewRequest("POST", genMusicUrl, bytes.NewBuffer(reqData))
	req.Header.Set("Authorization", "Bearer "+Token)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return
	}

	defer resp.Body.Close()

	var genResponse GenerateResp
	err = json.NewDecoder(resp.Body).Decode(&genResponse)
	if err != nil {
		return
	}

	return genResponse, nil
}

// GetFeed 查询详情
func (s *service) GetFeed(ids []string) (result []Clips, err error) {
	// token校验
	//if err = s.checkToken(); err != nil {
	//	return
	//}

	idsFormat := url.PathEscape(strings.Join(ids, ","))
	feedUrl := fmt.Sprintf("%s/api/feed/?ids=%s", BaseUrl, idsFormat)
	req, _ := http.NewRequest("GET", feedUrl, nil)
	req.Header.Set("Authorization", "Bearer "+Token)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("error reading response body: %v", err)
	}

	err = json.Unmarshal(bodyBytes, &result)
	if err != nil {
		fmt.Printf("Error decoding JSON response: %v\nResponse body: %s\n", err, bodyBytes)
		return nil, err
	}
	return result, nil
}

// GetToken getToken
func (s *service) GetToken(cookieStr string) (token string, err error) {
	var cookies []*http.Cookie
	cookies = s.parseCookieString(cookieStr)

	jar, _ := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
	sidUrl, _ := url.Parse(GetSidUrl)
	jar.SetCookies(sidUrl, cookies)

	client := &http.Client{
		Jar: jar,
	}

	sidResp, err := client.Get(sidUrl.String())
	if err != nil {
		return "", err
	}
	defer sidResp.Body.Close()

	var sidResponse SidResp
	_ = json.NewDecoder(sidResp.Body).Decode(&sidResponse)

	sid := ""
	if len(sidResponse.Response.Sessions) > 0 {
		sid = sidResponse.Response.Sessions[0].ID
		fmt.Println(sidResponse.Response.Sessions[0].ID)
	} else {
		err = errors.New("获取sessionId失败:Response.Sessions为空")
		return "", err
	}

	getTokenUrl := fmt.Sprintf("%s/%s/tokens?_clerk_js_version=4.72.0-snapshot.vc141245", GetTokenUrl, sid)
	tokenResp, err := client.Post(getTokenUrl, ContentType, nil)
	if err != nil {
		return "", err
	}
	defer tokenResp.Body.Close()

	var tokenResponse TokenResp
	bodyBytes, err := io.ReadAll(tokenResp.Body)
	if err != nil {
		return "", fmt.Errorf("error reading response body: %v", err)
	}

	if tokenResp.StatusCode != http.StatusOK {
		fmt.Printf("Error decoding JSON response: %v\nResponse body: %s\n", err, bodyBytes)
		fmt.Printf("请求失败，状态码: %d, 响应内容: %s\n", tokenResp.StatusCode, bodyBytes)
		return "", errors.New(fmt.Sprintf("请求失败，状态码: %d, 响应内容: %s\n", tokenResp.StatusCode, bodyBytes))
	}

	err = json.Unmarshal(bodyBytes, &tokenResponse)
	if err != nil {
		return "", err
	}

	if tokenResponse.Jwt == "" {
		return "", errors.New("获取token失败:token为空")
	}

	return tokenResponse.Jwt, nil
}

// KeepLive 账号保活
func (s *service) KeepLive() {
	ticker := time.NewTicker(time.Second * 5) // 创建一个定时器，每隔5秒触发一次
	defer ticker.Stop()                       // 确保在退出函数时停止定时器

	for {
		select {
		case <-ticker.C: // 当定时器触发时
			cookieStr := Conf.Cookie
			if cookieStr == "" {
				fmt.Println(CookieNotFound)
				continue
			}

			token, err := s.GetToken(cookieStr)
			if err != nil {
				fmt.Println(err.Error())
				continue
			}

			Token = token
			fmt.Println("协程账号保活token-" + token)
		}
	}
}

// parseCookieString 格式化cookie
func (s *service) parseCookieString(cookieStr string) []*http.Cookie {
	var cookies []*http.Cookie
	for _, cookiePair := range strings.Split(cookieStr, "; ") {
		parts := strings.Split(cookiePair, "=")
		if len(parts) == 2 {
			cookies = append(cookies, &http.Cookie{Name: parts[0], Value: parts[1]})
		}
	}
	return cookies
}

// checkToken token校验
func (s *service) checkToken() error {
	cookieStr := Conf.Cookie
	if cookieStr == "" {
		return errors.New(CookieNotFound)
	}

	tokenStr, err := s.GetToken(cookieStr)
	if err != nil {
		return err
	}

	if tokenStr == "" {
		return errors.New(TokenNotFound)
	}

	Token = tokenStr
	return nil
}
